namespace GYLite
{
    export enum ExpressType{
        CONST,
        VAR,
        FUNC,
        OPERATOR,
        EXPRESS,
        OTHER
    }
    export interface ExpStack
    {
        index:number;
    }
    /**量子技术之表达式解析器*/
    export class Express{        
        public static analyze(str:string):ExpTree
        {         
            if(str == null)
                return new ExpTree(ExpressType.CONST, null, "0");            
            str = (str+"");
            str = str.replace(/[^0-9a-zA-Z\.\+\-\*\/\%\(\)\,\^_]/g, "");            
            let arr:string[] = str.match(/\(|\)|\+|\-|\*|\/|\%|\,|\^|[.0-9a-zA-Z_]+/g);
            function input(curTree:ExpTree, code:string, arr:string[],stackObj:ExpStack=null):ExpTree
            {
                let expTree:ExpTree;
                let letter:string;
                if(code == null)//结束
                    return curTree;
                if(code == ")")
                {
                    --stackObj.index;
                    return curTree;
                }
                if(code == ",")//参数分隔符
                {
                    return input(curTree, arr[++stackObj.index], arr, stackObj);
                }
                letter = code.charAt(0);
                if(Number(code) == Number(code))
                {//常量
                    expTree = new ExpTree(ExpressType.CONST, curTree, code);
                }
                else if(letter >= "a" && letter <= "z" || letter >= "A" && letter <= "Z")
                {
                    if(arr[stackObj.index+1] == "(")
                    {//函数
                        expTree = input(new ExpTree(ExpressType.FUNC,curTree, code),arr[stackObj.index+=2],arr,stackObj);
                        code = arr[++stackObj.index];
                        if(code != ")")
                            throw(new Error("函数缺少结束括号:)，code:" + stackObj.index)); 
                    }                        
                    else
                        expTree = new ExpTree(ExpressType.VAR,curTree, code);//变量
                }
                else if(code == "(")
                {//子级表达式
                    expTree = input(new ExpTree(ExpressType.EXPRESS, curTree), arr[++stackObj.index], arr, stackObj);
                    code = arr[++stackObj.index];
                    if(code != ")")
                        throw(new Error("表达式缺少结束括号)，code:" + stackObj.index)); 
                }
                else
                {//运算符            
                    let operator:Operator = curTree.publicDef.operatorList[code];        
                    if(operator == null)
                    debugger;
                    if(curTree._rootValue == null)
                        curTree.addRootValue(code);
                    else if(operator._priority <= operator._priority)
                    {//运算优先级比当前节点低，创建新父级表达式
                        let newParent:ExpTree;
                        newParent = new ExpTree(ExpressType.EXPRESS, curTree.parent, code, [curTree]);                        
                        curTree = newParent;
                    }
                }
                if(expTree)
                {        
                    //写入当前节点前，预检测下一个运算符优先级比当前创建的节点高，则把当前节点写入新创建的子节点，然后把新创建的子节点作为当前创建的节点
                    let op1:Operator,op2:Operator;
                    op1 = curTree.publicDef.operatorList[curTree._rootValue];
                    if(op1)
                    {
                        let priority:number = curTree.type == ExpressType.FUNC?-1:op1._priority;
                        op2 = curTree.publicDef.operatorList[arr[stackObj.index+1]];
                        if(op2 && op2._priority > priority)
                        {
                            let newLeaf:ExpTree;
                            newLeaf = input(new ExpTree(ExpressType.EXPRESS, curTree, null, [expTree]), arr[++stackObj.index], arr, stackObj);
                            expTree = newLeaf;
                        }
                    }
                    
                    let n:number = curTree.addLeaf(expTree);
                    if(n > 0)
                        throw(new Error("参与运算的参数超出"+n+"个，code:" + stackObj.index));  
                }                    
                if((curTree.parent == null || !curTree.isFull()) && stackObj.index < arr.length-1)//节点数据已满或者到达根节点，继续后续的录入
                    curTree = input(curTree, arr[++stackObj.index], arr, stackObj);
                return curTree;
            }
            let expTree:ExpTree;
            let stackObj:ExpStack = {index:0};
            expTree = new ExpTree(ExpressType.EXPRESS);
            expTree = input(expTree, arr[stackObj.index], arr, stackObj);
            return expTree;
        }
    }
    export class Def{
        private static _globalDef:Def;
        public static getGlobalDef():Def{
            if(Def._globalDef == null)
                Def._globalDef = new Def;
            return Def._globalDef;
        }
        
        public operatorList:{[key:string]:Operator};        
        public constList:{[key:string]:any};
        public constructor()
        {
            let s= this;
            s.operatorList = {};            
            s.constList = {};
            s.addOpDef("+", new OpAdd(1));
            s.addOpDef("-", new OpSubtract(1));            
            s.addOpDef("*", new OpMultiply(2));
            s.addOpDef("/", new OpDivide(2));
            s.addOpDef("%", new OpReMainder(3));
            s.addOpDef("^", new OpPow(4));     
            s.addOpDef("int", new OpInt);
            s.addOpDef("max", new OpMax);
            s.addOpDef("min", new OpMin);
            s.addOpDef("rd", new OpRound);
            s.addOpDef("fl", new OpFloor);
            s.addOpDef("cl", new OpCeil);
            s.addOpDef("abs", new OpAbs);
            s.addOpDef("sin", new OpSin);
            s.addOpDef("cos", new OpCos);
            s.addOpDef("cos", new OpCos);
            s.addOpDef("cos", new OpCos);            
            s.addOpDef("rnd", new OpRnd());
        }
        /**增加运算符或者函数定义*/
        public addOpDef(code:string,op:Operator):void
        {            
            this.operatorList[code] = op;
            op.key = code;
        }
        /**增加常量定义*/
        public addConst(code:string,val:number):void
        {
            let s= this;
            s.constList[code] = val;
        }
    }
    export class ExpTree
    {
        protected _leafs:ExpTree[];        
        public _rootValue:string;
        public type:ExpressType;
        public parent:ExpTree;
        public _operator:Operator;
        /**语法树的公共定义集*/public publicDef:Def;
        constructor(type:ExpressType, parent:ExpTree=null, value:string=null,leafs:ExpTree[]=[])
        {
            let s = this;
            s._rootValue = value;            
            s.type = type;
            s.parent = parent;            
            s._leafs = leafs;
            let len:number;
            len = s._leafs.length;
            while(--len>-1)
                s._leafs[len].parent = parent;
            s.publicDef = s.parent?s.parent.publicDef:Def.getGlobalDef();
        }
        public addRootValue(val:string):void
        {
            let s= this;
            s._rootValue = val;
            if(s._leafs.length == 0)
                s._leafs[0] = new ExpTree(ExpressType.CONST, s.parent, "0");
        }
        public addLeaf(leaf:ExpTree):number
        {
            let s= this;
            let operator:Operator;            
            operator = s.publicDef.operatorList[s._rootValue]; 
            if(operator)
            {
                if(operator._length == -1)
                    return 0;
                if(s._leafs.length == operator._length)
                    return operator._length;
            }                
            this._leafs.push(leaf);
            return 0;
        }
        /**节点已经满*/
        public isFull():boolean
        {
            let s= this;            
            let operator:Operator;
            if(s._rootValue == null)
                return false;
            operator = s.publicDef.operatorList[s._rootValue]; 
            if(operator == null)
                throw(new Error("找不到运算符的规则:" + s._rootValue));                        
            return (operator._length == -1 || s._leafs.length == operator._length);
        }
       
        public getValue():any
        {
            let s = this;
            if(s._rootValue == null)
            {
                if(s._leafs[0] == null)
                    throw(new Error("表达式必须要有运算值或者左值!"));  
                return s._leafs[0].getValue();
            }
                
            if(s._leafs.length == 0)
            {
                let num:number = Number(s._rootValue);
                if(num == num)
                    return num;
            }

            return s.cal();
        }
        protected cal():any
        {
            let s= this;            
            let operator:Operator;
            if(s.type == ExpressType.VAR)
            {
                if(s.publicDef.constList[s._rootValue])
                    return s.publicDef.constList[s._rootValue];                
                return s._rootValue;
            }
            s._operator = operator = s.publicDef.operatorList[s._rootValue]; 
            if(operator == null)
            {
                throw(new Error("找不到运算符的规则:" + s._rootValue));  
            }
            let params:any[];
            let i:number,len:number;
            params = [];
            len = s._leafs.length;
            for(i=0;i<len;++i)
                params.push(s._leafs[i]?s._leafs[i].getValue():0);
            return operator.cal.apply(operator, params);
        }
        /**打印公式*/
        public print():string
        {
            let s= this;
            let params:any[];
            let i:number,len:number;            
            if(s._rootValue == null)
            {
                if(s._leafs[0] == null)
                    throw(new Error("表达式必须要有运算值或者左值!"));  
                return s._leafs[0].print();
            }
                
            if(s._leafs.length == 0)
            {                
                return s._rootValue;
            }

            let operator:Operator;
            if(s.type == ExpressType.VAR)
            {
                if(s.publicDef.constList[s._rootValue])
                    return s.publicDef.constList[s._rootValue];                
                return s._rootValue;
            }
            s._operator = operator = s.publicDef.operatorList[s._rootValue]; 
            if(operator == null)
            {
                throw(new Error("找不到运算符的规则:" + s._rootValue));  
            }
            let str:string;
            let expTree:ExpTree;
            params = [];
            len = s._leafs.length;
            for(i=0;i<len;++i)
            {
                expTree = s._leafs[i];
                str = expTree?expTree.print():"0";
                if(expTree && expTree.type != ExpressType.FUNC && expTree._operator && expTree._operator._priority < s._operator._priority)
                    params.push("("+str+")");
                else
                    params.push(str);
            }
                
            return operator.print.apply(operator, params);
        }
    }
    export class Operator{
        public key:string;
        /**优先级*/public _priority:number;
        /**参数数量*/public _length:number;
        public cal:Function;
        public _thisObj:any;
        /**
         * @param priority 默认-1，优先级 值越大优先级越高
         * @param length 默认2，运算参数长度
         * @param thisObj 默认null，运算执行函数this指向
         * @param func 默认null，运算执行函数
        */
        constructor(priority:number=-1, length:number=2, thisObj:any = null, func:Function = null)
        {
            let s= this;
            s._priority = priority;
            s._length = length;
            s._thisObj = thisObj;
            s.cal = func?func:s.defaultCal;
        }
        print(...args):string{return "["+this.key+"("+args.toString()+")="+this.cal(...args)+"]";}
        /**默认的运算执行函数*/
        defaultCal(...args):number
        {
            return args[0]+args[1];
        }
    }
    export class OpAdd extends Operator{
        print(...args):string{return args[0] + "+" + args[1];}
        defaultCal(...args):number{return args[0] + args[1];}
    }
    export class OpSubtract  extends Operator{
        print(...args):string{return args[0] + "-" + args[1];}
        defaultCal(...args):number{return args[0] - args[1];}
    }
    export class OpMultiply extends Operator{
        print(...args):string{return args[0] + "*" + args[1];}
        defaultCal(...args):number{return args[0] * args[1];}
    }
    export class OpDivide extends Operator{
        print(...args):string{return args[0] + "/" + args[1];}
        defaultCal(...args):number{return args[0] / args[1];}
    }
    export class OpReMainder extends Operator{
        print(...args):string{return args[0] + "%" + args[1];}
        defaultCal(...args):number{return args[0] % args[1];}
    }
    export class OpPow extends Operator{
        print(...args):string{return args[0] + "^" + args[1];}
        defaultCal(...args):number{return Math.pow(args[0], args[1]);}
    }
    export class OpInt extends Operator{
        constructor(priority:number=-1, length:number=1, thisObj:any = null, func:Function = null){super(priority, length, thisObj, func);}
        print(...args):string{return ""+args[0];}
        defaultCal(...args):number{return parseInt(args[0]);}
    }
    export class OpMax extends Operator{
        constructor(priority:number=-1, length:number=999, thisObj:any = null, func:Function = null){super(priority, length, thisObj, func);}        
        defaultCal(...args):number{return Math.max(...args);}
    }
    export class OpMin extends Operator{        
        constructor(priority:number=-1, length:number=999, thisObj:any = null, func:Function = null){super(priority, length, thisObj, func);}        
        defaultCal(...args):number{return Math.min(...args);}
    }
    export class OpRound extends Operator{
        constructor(priority:number=-1, length:number=1, thisObj:any = null, func:Function = null){super(priority, length, thisObj, func);}        
        defaultCal(...args):number{return Math.round(args[0]);}
    }
    export class OpFloor extends Operator{
        constructor(priority:number=-1, length:number=1, thisObj:any = null, func:Function = null){super(priority, length, thisObj, func);}        
        defaultCal(...args):number{return Math.floor(args[0]);}
    }
    export class OpCeil extends Operator{
        constructor(priority:number=-1, length:number=1, thisObj:any = null, func:Function = null){super(priority, length, thisObj, func);}        
        defaultCal(...args):number{return Math.ceil(args[0]);}
    }
    export class OpAbs extends Operator{
        constructor(priority:number=-1, length:number=1, thisObj:any = null, func:Function = null){super(priority, length, thisObj, func);}        
        defaultCal(...args):number{return Math.abs(args[0]);}
    }
    export class OpSin extends Operator{
        constructor(priority:number=-1, length:number=1, thisObj:any = null, func:Function = null){super(priority, length, thisObj, func);}        
        defaultCal(...args):number{return Math.sin(args[0]);}
    }
    export class OpCos extends Operator{
        constructor(priority:number=-1, length:number=1, thisObj:any = null, func:Function = null){super(priority, length, thisObj, func);}        
        defaultCal(...args):number{return Math.cos(args[0]);}
    }
    export class OpRnd extends Operator{
        constructor(priority:number=-1, length:number=2, thisObj:any = null, func:Function = null){super(priority, length, thisObj, func);}        
        defaultCal(...args):number{return args[0] + Math.random()*args[1];}
    }    
}